package com.tea.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.model.*;
import com.tea.config.oss.OssProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.UUID;

/**
 * 阿里云OSS工具类
 * @author tea-shop
 */
@Slf4j
@Component
@ConditionalOnProperty(prefix = "aliyun.oss", name = "enabled", havingValue = "true")
public class OssUtil {
    
    @Resource
    private OSS ossClient;
    
    @Resource
    private OssProperties ossProperties;
    
    /**
     * 上传文件
     * @param file 文件
     * @return 文件访问URL
     * @throws IOException IO异常
     */
    public String uploadFile(MultipartFile file) throws IOException {
        return uploadFile(file, null);
    }
    
    /**
     * 上传文件到指定目录
     * @param file 文件
     * @param directory 目录（如：image/、video/）
     * @return 文件访问URL
     * @throws IOException IO异常
     */
    public String uploadFile(MultipartFile file, String directory) throws IOException {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
        
        // 验证文件类型
        String fileType = getFileType(file.getOriginalFilename());
        if ("unknown".equals(fileType)) {
            throw new IllegalArgumentException("不支持的文件格式");
        }
        
        // 生成文件名
        String fileName = generateFileName(file.getOriginalFilename(), directory);
        
        // 上传文件
        try (InputStream inputStream = file.getInputStream()) {
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(file.getSize());
            metadata.setContentType(file.getContentType());
            
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    ossProperties.getBucketName(), fileName, inputStream, metadata);
            
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            
            log.info("文件上传成功: {}, ETag: {}", fileName, result.getETag());
            
            // 直接传入不包含路径前缀的文件名
            String fileNameWithoutPrefix = fileName;
            if (fileName.startsWith(ossProperties.getPathPrefix())) {
                fileNameWithoutPrefix = fileName.substring(ossProperties.getPathPrefix().length());
            }
            return ossProperties.getFileUrl(fileNameWithoutPrefix);
        } catch (Exception e) {
            log.error("文件上传失败: {}", fileName, e);
            throw new RuntimeException("文件上传失败: " + e.getMessage());
        }
    }
    
    /**
     * 上传字节数组
     * @param bytes 字节数组
     * @param fileName 文件名
     * @param contentType 内容类型
     * @return 文件访问URL
     */
    public String uploadBytes(byte[] bytes, String fileName, String contentType) {
        String fullFileName = ossProperties.getPathPrefix() + fileName;
        
        try (InputStream inputStream = new ByteArrayInputStream(bytes)) {
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(bytes.length);
            metadata.setContentType(contentType);
            
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    ossProperties.getBucketName(), fullFileName, inputStream, metadata);
            
            PutObjectResult result = ossClient.putObject(putObjectRequest);
            
            log.info("字节数组上传成功: {}, ETag: {}", fullFileName, result.getETag());
            
            return ossProperties.getFileUrl(fileName);
        } catch (Exception e) {
            log.error("字节数组上传失败: {}", fullFileName, e);
            throw new RuntimeException("字节数组上传失败: " + e.getMessage());
        }
    }
    
    /**
     * 删除文件
     * @param fileName 文件名（不包含路径前缀）
     * @return 是否删除成功
     */
    public boolean deleteFile(String fileName) {
        String fullFileName = ossProperties.getPathPrefix() + fileName;
        
        try {
            ossClient.deleteObject(ossProperties.getBucketName(), fullFileName);
            log.info("文件删除成功: {}", fullFileName);
            return true;
        } catch (Exception e) {
            log.error("文件删除失败: {}", fullFileName, e);
            return false;
        }
    }
    
    /**
     * 删除文件（通过完整URL）
     * @param fileUrl 文件完整URL
     * @return 是否删除成功
     */
    public boolean deleteFileByUrl(String fileUrl) {
        if (fileUrl == null || fileUrl.isEmpty()) {
            return false;
        }
        
        // 从URL中提取文件名
        String fileName = extractFileNameFromUrl(fileUrl);
        if (fileName == null) {
            log.warn("无法从URL中提取文件名: {}", fileUrl);
            return false;
        }
        
        return deleteFile(fileName);
    }
    
    /**
     * 检查文件是否存在
     * @param fileName 文件名（不包含路径前缀）
     * @return 是否存在
     */
    public boolean doesFileExist(String fileName) {
        String fullFileName = ossProperties.getPathPrefix() + fileName;
        
        try {
            return ossClient.doesObjectExist(ossProperties.getBucketName(), fullFileName);
        } catch (Exception e) {
            log.error("检查文件是否存在失败: {}", fullFileName, e);
            return false;
        }
    }
    
    /**
     * 获取文件信息
     * @param fileName 文件名（不包含路径前缀）
     * @return 文件信息
     */
    public ObjectMetadata getFileMetadata(String fileName) {
        String fullFileName = ossProperties.getPathPrefix() + fileName;
        
        try {
            return ossClient.getObjectMetadata(ossProperties.getBucketName(), fullFileName);
        } catch (Exception e) {
            log.error("获取文件信息失败: {}", fullFileName, e);
            return null;
        }
    }
    
    /**
     * 生成文件名
     * @param originalFilename 原始文件名
     * @param directory 目录
     * @return 完整文件名
     */
    private String generateFileName(String originalFilename, String directory) {
        String extension = getFileExtension(originalFilename);
        String uuid = UUID.randomUUID().toString().replace("-", "");
        
        StringBuilder fileName = new StringBuilder(ossProperties.getPathPrefix());
        
        if (directory != null && !directory.isEmpty()) {
            if (!directory.endsWith("/")) {
                directory += "/";
            }
            fileName.append(directory);
        }
        
        fileName.append(uuid);
        if (!extension.isEmpty()) {
            fileName.append(".").append(extension);
        }
        
        return fileName.toString();
    }
    
    /**
     * 从URL中提取文件名
     * @param fileUrl 文件URL
     * @return 文件名
     */
    private String extractFileNameFromUrl(String fileUrl) {
        try {
            String pathPrefix = ossProperties.getPathPrefix();
            int prefixIndex = fileUrl.indexOf(pathPrefix);
            if (prefixIndex != -1) {
                return fileUrl.substring(prefixIndex + pathPrefix.length());
            }
            
            // 如果没有找到路径前缀，尝试从最后一个/后面提取
            int lastSlashIndex = fileUrl.lastIndexOf("/");
            if (lastSlashIndex != -1 && lastSlashIndex < fileUrl.length() - 1) {
                return fileUrl.substring(lastSlashIndex + 1);
            }
        } catch (Exception e) {
            log.error("从URL提取文件名失败: {}", fileUrl, e);
        }
        return null;
    }
    
    /**
     * 获取文件类型
     * @param fileName 文件名
     * @return 文件类型
     */
    private String getFileType(String fileName) {
        String extension = getFileExtension(fileName).toLowerCase();
        
        if (extension.matches("(jpg|jpeg|png|gif|webp|svg|bmp|tiff|ico|avif)")) {
            return "image";
        } else if (extension.matches("(mp4|avi|mov|mkv|webm|wmv|flv|m4v|mpeg|3gp)")) {
            return "video";
        } else if (extension.matches("(mp3|wav|ogg|flac|aac|wma)")) {
            return "audio";
        } else if (extension.matches("(pdf|doc|docx|xls|xlsx|ppt|pptx|txt|rtf)")) {
            return "document";
        } else if (extension.matches("(zip|rar|7z|gz|tar)")) {
            return "archive";
        }
        return "unknown";
    }
    
    /**
     * 获取文件扩展名
     * @param fileName 文件名
     * @return 扩展名
     */
    private String getFileExtension(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "";
        }
        int dotIndex = fileName.lastIndexOf('.');
        if (dotIndex > 0 && dotIndex < fileName.length() - 1) {
            return fileName.substring(dotIndex + 1);
        }
        return "";
    }
    
    /**
     * 从URL下载图片并上传到OSS
     * @param imageUrl 图片URL
     * @return OSS文件访问URL
     * @throws Exception 下载或上传异常
     */
    public String uploadFromUrl(String imageUrl) throws Exception {
        if (imageUrl == null || imageUrl.isEmpty()) {
            throw new IllegalArgumentException("图片URL不能为空");
        }
        
        // 如果已经是OSS链接，直接返回
        if (imageUrl.contains("aliyuncs.com")) {
            return ensureHttpsPrefix(imageUrl);
        }
        
        // 下载图片并上传到OSS
        URL url = new URL(imageUrl);
        try (InputStream inputStream = url.openStream()) {
            // 提取文件名
            String fileName = extractFileNameFromImageUrl(imageUrl);
            
            // 读取图片数据
            byte[] imageBytes = inputStream.readAllBytes();
            
            // 获取内容类型
            String contentType = getContentTypeFromFileName(fileName);
            
            // 上传到OSS
            String ossUrl = uploadBytes(imageBytes, fileName, contentType);
            
            // 确保返回的OSS链接包含https://前缀
            String finalOssUrl = ensureHttpsPrefix(ossUrl);
            
            log.info("图片从URL迁移成功: {} -> {}", imageUrl, finalOssUrl);
            return finalOssUrl;
        }
    }
    
    /**
     * 从图片URL中提取文件名
     * @param imageUrl 图片URL
     * @return 文件名
     */
    private String extractFileNameFromImageUrl(String imageUrl) {
        try {
            String path = new URL(imageUrl).getPath();
            String fileName = path.substring(path.lastIndexOf('/') + 1);
            
            // 如果没有扩展名，添加默认扩展名
            if (!fileName.contains(".")) {
                fileName += ".jpg";
            }
            
            // 添加时间戳避免重名
            String name = fileName.substring(0, fileName.lastIndexOf('.'));
            String extension = fileName.substring(fileName.lastIndexOf('.'));
            
            return "goods/" + name + "_" + System.currentTimeMillis() + extension;
            
        } catch (Exception e) {
            log.warn("提取文件名失败，使用默认名称: {}", imageUrl);
            return "goods/image_" + System.currentTimeMillis() + ".jpg";
        }
    }
    
    /**
     * 根据文件名获取内容类型
     * @param fileName 文件名
     * @return 内容类型
     */
    private String getContentTypeFromFileName(String fileName) {
        if (fileName == null) {
            return "image/jpeg";
        }
        
        String extension = fileName.toLowerCase();
        if (extension.endsWith(".jpg") || extension.endsWith(".jpeg")) {
            return "image/jpeg";
        } else if (extension.endsWith(".png")) {
            return "image/png";
        } else if (extension.endsWith(".gif")) {
            return "image/gif";
        } else if (extension.endsWith(".webp")) {
            return "image/webp";
        } else if (extension.endsWith(".bmp")) {
            return "image/bmp";
        } else {
            return "image/jpeg"; // 默认类型
        }
    }
    
    /**
     * 确保URL包含https://前缀
     * @param url 原始URL
     * @return 包含https://前缀的URL
     */
    private String ensureHttpsPrefix(String url) {
        if (url == null || url.isEmpty()) {
            return url;
        }
        
        // 如果已经包含协议前缀，直接返回
        if (url.startsWith("https://") || url.startsWith("http://")) {
            return url;
        }
        
        // 添加https://前缀
        return "https://" + url;
    }
}